Solution: Find The Duplicate Number
Let's solve the Find The Duplicate Number problem using the the Fast and Slow pattern.
We'll cover the following
Statement#
Given an unsorted array of positive numbers, nums, such that the values lie in the range , inclusive, and that there are numbers in the array, find and return the duplicate number present in nums. There is only one repeated number in nums.
Note: You cannot modify the given array
nums. You have to solve the problem using only constant extra space.
Constraints:
nums.length-
nums[i] - All the integers in
numsare unique except for one integer that will appear more than once.
Solution#
We solve this problem using fast and slow pointers technique, without modifying the nums array and using only constant extra space.
For this problem, the duplicate number will create a cycle in the nums array. The cycle in the nums array helps identify the duplicate number.
To find the cycle, we’ll move in the nums array using the function, where is the index of the array. This function constructs the following sequence to move:
In the sequence above, every new element is an element in nums present at the index of the previous element.
Let’s say we have an array, . We’ll start with , which is , present at the index of the array and then move to , which is , present at the index. Since we found at the index, we’ll move to the index, and so on. This example shows that if we’re given an array of length , with values in the range , we can use this traversal technique to visit all the locations in the array.
The following example illustrates this traversal:
1 of 11
2 of 11
3 of 11
4 of 11
5 of 11
6 of 11
7 of 11
8 of 11
9 of 11
10 of 11
11 of 11
As seen above, we’ve found that there is a cycle in an array with a duplicate number. Now, the problem is to find the entry point of the cycle, which will be our duplicate number.
We solve this problem in two parts using the slow and fast pointers.
In the first part, the slow pointer moves once, while the fast pointer moves twice as fast as the slow pointer until both of the pointers meet each other. Since the fast pointer is moving twice as fast as the slow pointer, it will be the first one to enter and move around the cycle. At some point after the slow pointer also enters and moves in the cycle, the fast pointer will meet the slow pointer. This will be the intersection point.
Note: The intersection point of the two pointers is, in the general case, not the entry point of the cycle.
Let’s look at a visual representation of the first part of our solution:
1 of 9
2 of 9
3 of 9
4 of 9
5 of 9
6 of 9
7 of 9
8 of 9
9 of 9
In part two, we’ll start moving again in the cycle, but this time, we’ll slow down the fast pointer so that it moves with the same speed as the slow pointer.
Let’s look at the journeys of the two pointers in part two:
-
The
slowpointer will start from the position. -
The
fastpointer will start from the intersection point. -
After a certain number of steps, let’s call it , the
slowpointer meets thefastpointer. This is the ending point for both pointers. -
This common ending position will be the entry point of the cycle.
Let’s look at the visual presentation of the second part of our solution:
1 of 3
2 of 3
3 of 3
Now, let’s try to understand how it is that our solution is able to always locate the entry point of the cycle.
Let’s return to the example we just discussed, using this graphical representation:
-
is the intersection point where the
slowandfastpointers will meet. -
is the entry point of the cycle, which is our duplicate number.
The fast pointer is traversing two times faster than the slow pointer. This can be represented by the following equation:
———
Here, represents the number of elements traversed.
Let’s look at the following diagram to see the steps taken by the slow and fast pointers from the starting point to the intersection point:
In the diagram above:
-
Green represents the entry point of the cycle.
-
Blue represents the intersection point.
-
Yellow represents the starting point.
-
represents the steps taken from the starting point to the entry point.
-
represents the steps taken to reach the intersection point from the entry point.
-
represents the cycle length, in terms of the number of steps taken to go once around the cycle.
With this setup in mind, let’s see the distance traveled by the slow and fast pointers.
The slow pointer travels steps from the starting point to the entry point of the cycle and then takes steps from the entry point to the intersection point of the cycle, that is, the point where both pointers intersect. So, we can express the distance traveled by the slow pointer in the form of this equation:
———
In the time it takes the slow pointer to travel steps, the fast pointer, since it’s traveling twice as fast as the slow pointer, will have also traveled around the cycle at least once. So, we can say the fast pointer, first, travels steps from the starting point to the entry point of the cycle, then travels at least a cycle, and at the end travels steps from the entry point to the intersection point of the cycle. Now, we can express the distance traveled by the fast pointer as the following equation:
———
Recall eq.
———
If we substitute the equivalent expression of given in eq. and the equivalent expression of given in eq. into eq. , we get:
Let’s simplify this equation:
Therefore, the distance from the starting point to the intersection point, , equals .
We can also re-arrange this equality as follows:
Let’s consult our diagram again:
As we can see, is, in fact, the distance from the intersection point back to the entry point. This illustrates why, when we move one pointer forward, starting at the intersection point, and another pointer from the starting point, the point where they meet is the entry point of the cycle.
Note: The proof above does not consider the case where is longer than the length of the cycle. In this situation, it’s possible that the
fastpointer will go around the cycle more than once. To express this more general case, we can say that the distance covered by thefastpointer from the entry point to the intersection point is: , where is a positive integer. As a result, our substitution will take this form: , which simplifies to , that is: . This simply means that after going around the cycle times, thefastpointer will still be steps behind the entry point of the cycle.
Let’s look at the implementation of the solution discussed above:
Time complexity#
The time complexity of the algorithm is , where is the length of nums. This is because, in each part of the solution, the slow pointer traverses nums just once.
Space complexity#
The algorithm takes space complexity, since we only used constant space to store the fast and slow pointers.
Find The Duplicate Number
Palindrome Linked List